/* * Copyright © 2010 Martin Riedel * * This file is part of TransFile. * * TransFile is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * TransFile is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with TransFile. If not, see <http://www.gnu.org/licenses/>. */ package net.sourceforge.transfile.ui.swing; import static net.sourceforge.jenerics.collections.CollectionsTools.array; import static net.sourceforge.transfile.ui.swing.GUITools.horizontalFlow; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ActionEvent; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.EventObject; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.DefaultCellEditor; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.CellEditorListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableModel; import net.sourceforge.transfile.TransFile; import net.sourceforge.jenerics.i18n.Translator; import net.sourceforge.transfile.settings.Settings; /** * Preferences frame that allows the user to configure the application variables. * <br>These variables can be found in {@link net.sourceforge.transfile.settings.Settings}. * <br>When the user clicks "Ok", the changes are committed to the Preferences API via {@link Settings#getPreferences}. * * @author codistmonk (creation 2010-05-09) * */ public class PreferencesFrame extends JDialog { private final TableModel tableModel; /** * * @param owner * <br>Should not be null * <br>Reference parameter */ public PreferencesFrame(final JFrame owner) { super(owner, "TransFile Preferences"); // I decided to use a table to edit the properties because I thought it was easier // for both the developers and the user; but that can be changed if necessary // TODO add specific editors and data validation for each property this.tableModel = createTableModel(); this.setLayout(new BorderLayout()); this.add(new JScrollPane(this.createTable()), BorderLayout.CENTER); this.add(horizontalFlow( new JButton(this.new OkAction()), new JButton(this.new CancelAction()) ), BorderLayout.SOUTH); this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); this.pack(); this.setLocationRelativeTo(owner); } final void saveSettings() { for (int i = 0; i < this.tableModel.getRowCount(); ++i) { final Object key = this.tableModel.getValueAt(i, 0); final Object value = this.tableModel.getValueAt(i, 1); Settings.getPreferences().put(key.toString(), value.toString()); if ("locale".equals(key)) { Translator.getDefaultTranslator().setLocale(Translator.createLocale(value.toString())); } if ("log_level".equals(key)) { Logger.getLogger(TransFile.PACKAGE_NAME).setLevel(Level.parse(value.toString())); } } } /** * * @return * <br>A new value * <br>A non-null value */ private final JTable createTable() { final JTable result = new JTable(this.tableModel); result.setToolTipText("Double-click to edit a value"); result.getTableHeader().setReorderingAllowed(false); result.setDefaultEditor(Object.class, new CellEditor(result.getDefaultEditor(Object.class))); return result; } /** * * TODO doc * * @author codistmonk (creation 2010-05-11) * */ private static final class CellEditor implements TableCellEditor { private final TableCellEditor defaultCellEditor; private TableCellEditor currentCellEditor; /** * * @param defaultCellEditor * <br>Should not be null * <br>Shared parameter */ public CellEditor(final TableCellEditor defaultCellEditor) { this.defaultCellEditor = defaultCellEditor; this.currentCellEditor = this.defaultCellEditor; } /** * {@inheritDoc} */ @Override public final Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) { if ("locale".equals(table.getValueAt(row, 0))) { this.currentCellEditor = new DefaultCellEditor(new JComboBox(Translator.getDefaultTranslator().getAvailableLocales())); } else if ("log_level".equals(table.getValueAt(row, 0))) { this.currentCellEditor = new DefaultCellEditor(new JComboBox(LOG_LEVELS)); } else { this.currentCellEditor = this.defaultCellEditor; } return this.currentCellEditor.getTableCellEditorComponent(table, value, isSelected, row, column); } /** * {@inheritDoc} */ @Override public final Object getCellEditorValue() { return this.currentCellEditor.getCellEditorValue(); } /** * {@inheritDoc} */ @Override public final void addCellEditorListener(final CellEditorListener listener) { this.currentCellEditor.addCellEditorListener(listener); } /** * {@inheritDoc} */ @Override public final void cancelCellEditing() { this.currentCellEditor.cancelCellEditing(); } /** * {@inheritDoc} */ @Override public final boolean isCellEditable(final EventObject event) { return this.currentCellEditor.isCellEditable(event); } /** * {@inheritDoc} */ @Override public final void removeCellEditorListener(final CellEditorListener listener) { this.currentCellEditor.removeCellEditorListener(listener); } /** * {@inheritDoc} */ @Override public final boolean shouldSelectCell(final EventObject event) { return this.currentCellEditor.shouldSelectCell(event); } /** * {@inheritDoc} */ @Override public final boolean stopCellEditing() { return this.currentCellEditor.stopCellEditing(); } private static final long serialVersionUID = -3204827079123577279L; private static final Level[] LOG_LEVELS = array( Level.ALL, Level.CONFIG, Level.FINE, Level.FINER, Level.FINEST, Level.INFO, Level.OFF, Level.SEVERE, Level.WARNING ); static { Arrays.sort(LOG_LEVELS, new Comparator<Level>() { @Override public final int compare(final Level level1, final Level level2) { return new Integer(level1.intValue()).compareTo(level2.intValue()); } }); } } /** * Saves the settings and closes the preference frame. * @author codistmonk (creation 2010-05-09) * */ private final class OkAction extends AbstractAction { public OkAction() { super("Ok"); } @Override public final void actionPerformed(final ActionEvent event) { PreferencesFrame.this.saveSettings(); PreferencesFrame.this.dispose(); } private static final long serialVersionUID = -7051752040024110888L; } /** * Closes the preference frame without saving the settings. * @author codistmonk (creation 2010-05-09) * */ private final class CancelAction extends AbstractAction { public CancelAction() { super("Cancel"); } @Override public final void actionPerformed(final ActionEvent event) { PreferencesFrame.this.dispose(); } private static final long serialVersionUID = -8284492092950897347L; } private static final long serialVersionUID = 4747810436442554432L; /** * Creates a new table model with 2 columns "key" and "value", initialized with data from the {@link Settings} * if they are defined. * <br>Otherwise, data from {@code defaultProperties} are used. * <br>The keys are extracted from {@code defaultProperties}. * @return * <br>A new value * <br>A non-null value */ @SuppressWarnings("unchecked") private static final DefaultTableModel createTableModel() { final DefaultTableModel result = new DefaultTableModel(new Object[] { "key", "value" }, 0) { @Override public final boolean isCellEditable(final int row, final int column) { return column == 1; } private static final long serialVersionUID = 8437021152739655775L; }; for (final String fieldName : Settings.getConstantFieldNames()) { final String key = fieldName.toLowerCase(); result.addRow(new Object[] { key, Settings.getPreferences().get(key, Settings.getConstantAsString(fieldName)) }); } Collections.sort(result.getDataVector(), new Comparator<Vector<String>>() { @Override public final int compare(final Vector<String> row1, final Vector<String> row2) { return row1.get(0).compareTo(row2.get(0)); } }); return result; } }